module IRQ (
  input enable,

  input ecall,
  input mret,
  input [63:0] pc_i,

  input unsupport_op,
  input ex_intr,
  input mie_i,

  input [63:0] mtvec_i,
  input [63:0] mepc_i,

  output raise_intr,
  output raise_hard_intr,

  output [63:0] mepc_o,
  output mepc_valid_o,
  output [63:0] mcause_o,
  output mcause_valid_o,
  output [63:0] pc_o,
  output pc_valid_o

);
  localparam MCAUSE_INTR = {1'b1,63'b0};
  localparam MCAUSE_ECALL_M  = 64'd11|MCAUSE_INTR;
  localparam MCAUSE_EX_INT_M = 64'd7|MCAUSE_INTR;
  localparam MCAUSE_ILLEGAL_INSTRUCTION = 64'd2;


  wire soft_intr = ecall|unsupport_op;
  wire hard_intr = mie_i & (ex_intr);
   
  wire [63:0] hard_intr_cause = {64{ex_intr}}&MCAUSE_EX_INT_M;
  wire [63:0] sort_intr_cause = {64{ecall}}&{MCAUSE_ECALL_M}|{64{unsupport_op}}&MCAUSE_ILLEGAL_INSTRUCTION;
  assign raise_intr = enable&(soft_intr | hard_intr)&~mret;

  // assign mepc_o = {64{soft_intr}}&pc_i|{64{(~soft_intr)&hard_intr}}&{pc_i+64'h4};
  assign mepc_o = pc_i;
  assign mepc_valid_o = raise_intr;
  assign mcause_o = {64{soft_intr}}&sort_intr_cause | {64{(~soft_intr)&hard_intr}}&hard_intr_cause;
  assign mcause_valid_o = raise_intr;
  assign pc_o = {64{raise_intr}}&mtvec_i | {64{mret}}&mepc_i;
  assign pc_valid_o = enable&(raise_intr|mret);
  
  assign raise_hard_intr = enable&(hard_intr&~(soft_intr|mret));
endmodule
